import hashlib
import hmac
import json
import os.path
import random
import threading
import time
import urllib.parse
import datetime
import re

import requests

user_data = {}
cookie_idx = 0


def start():
    init_global_data()
    set_cookie()
    load_userid()
    get_doc_info('1103021', '02068_06')
    get_patient_list()
    threading.Thread(target=keep_alive).start()
    get_schedule_list()


def keep_alive():
    while True:
        time.sleep(100)
        load_userid()


def init_global_data():
    global user_data

    date = user_data['date'] = (datetime.datetime.now() + datetime.timedelta(days=7)).strftime('%Y-%m-%d')
    week = user_data['visitWeekName'] = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'][
        datetime.datetime.strptime(user_data['date'], '%Y-%m-%d').weekday()]

    order_info = {'date': date, 'visitWeekName': week, 'deptId': '1103021', 'doctorId': '02068_06'}
    print("预约时间:", date, week)

    order_info['doctorTitle'] = ''
    order_info['deptName'] = ''
    order_info['doctorName'] = ''

    order_info['birthday'] = ''
    order_info['patientId'] = ''
    order_info['patientName'] = ''
    order_info['patCardNo'] = ''

    schedule_info = {'birthday': '', 'visitBeginTime': '', 'visitEndTime': ''}
    user_data['order_info'] = order_info
    user_data['schedule_info'] = schedule_info


def get_doc_info(dept_id, doctor_id):
    order_info = user_data['order_info']
    order_info['deptId'] = dept_id
    order_info['doctorId'] = doctor_id

    url = 'https://mp.med.gzhc365.com/api/register/doctordetail?hisId=153&platformSource=1&platformId=153'
    params = {
        'deptId': dept_id,
        'doctorId': doctor_id
    }
    data = wrapped_fetch(url, params)
    order_info['deptName'] = data['deptName']
    order_info['doctorName'] = data['doctorName']
    order_info['doctorTitle'] = data['doctorTitle']
    return data


def get_schedule_list():
    """检测排班信息"""
    while True:
        time.sleep(0.3)
        if os.path.exists(".data/schedulelist.json"):
            with open(".data/schedulelist.json", 'r', encoding='utf-8') as f:
                content = f.read()
                data = json.loads(content)
                if 'data' not in data or 'itemList' not in data['data']:
                    print("没有数据")
                    continue
                data = data['data']

                item_list = data['itemList']
                size = len(item_list)
                # print("排班信息:", size)
                if data['scheduleDate'] != user_data['order_info']['date']:
                    # print("日期不一致", data['scheduleDate'], user_data['order_info']['date'])
                    continue
                user_data['order_info']['scheduleDate'] = data['scheduleDate']
                if size > 0:
                    """最多预约8次"""
                    times = min(8, size)
                    for i in range(times):
                        schedule = item_list[random.randint(0, size - 1)]
                        time.sleep(1)
                        t = threading.Thread(target=reg_order, args=(user_data['order_info'], schedule))
                        t.start()
                    print("预约成功,退出")
                break


def get_patient_list():
    global user_data
    order_info = user_data['order_info']
    url = 'https://mp.med.gzhc365.com/api/personal/getpatientslist?hisId=153&platformSource=1&platformId=153'
    params = {}
    data = wrapped_fetch(url, params)
    print(data)
    patient = None
    if data:
        if 'cardList' in data:
            patients = data['cardList']
            if len(patients) > 1:
                print("选择就诊人:")
                index = 0
                for p in patients:
                    print("就诊人:", index, p['patientName'])
                    index = index + 1
                while True:
                    index = input("输入就诊人序号:")
                    index = int(index)
                    if index < len(patients):
                        patient = patients[index]
                        break

            if len(patients) == 1:
                print("找不到就诊人,使用第一个")
                patient = patients[0]
        else:
            print("获取就诊人列表失败")
    else:
        print("获取就诊人列表失败")
    print(patient)
    if patient:
        order_info.update(patient)
        print("找到就诊人", order_info)
    return data


def load_userid():
    headers = user_data['headers']
    response = requests.get(
        url="https://mp.med.gzhc365.com/api/user/userinfo/wx?hisId=153&platformSource=1&platformId=153",
        headers=headers, verify='DigiCert_Global_Root_CA.crt')
    now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    # 打印响应状态码和响应体
    print(now, "Response status:", response.status_code)
    body = response.text
    print(now, "Response body:", body)
    resp = json.loads(body)
    if resp and resp['code'] == 999:
        print("Error! login failed!")
        return False

    uid = resp['data']['id']
    user_data['uid'] = uid
    print("uid:", uid)


def set_cookie():
    global cookie_idx

    cookie = input('输入cookie:')
    print(cookie)
    intype = type(cookie)
    print(intype)
    if len(cookie) > 2:
        cookie_idx = cookie_idx + 1
        file = open('.data/cookie_' + str(cookie_idx), 'w+')
        file.write(cookie)
    else:
        file = open('.data/cookie_' + cookie, 'r')
        cookie = file.readline()
        print(cookie)

    headers = {
        "user-agent": "Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, "
                      "like Gecko) Version/4.0 Chrome/111.0.5563.116 Mobile Safari/537.36 XWEB/1110039 "
                      "MMWEBSDK/20231002 MMWEBID/4223 MicroMessenger/8.0.43.2480(0x28002B51) WeChat/arm64 Weixin "
                      "NetType/WIFI Language/zh_CN ABI/arm64",
        "his-id": "153", "hc-src-hisid": "153", "hc-proj-info": "project/wisdom-hospital;type/h5;ch/wechat;ver/2.0",
        'cookie': cookie}
    user_data['headers'] = headers


def reg_order(order_info, schedule_info):
    global user_data
    url = 'https://mp.med.gzhc365.com/api/register/generatororder?hisId=153&platformSource=1&platformId=153'
    params = {
        'deptId': order_info['deptId'],
        'doctorId': order_info['doctorId'],
        'scheduleId': schedule_info['scheduleId'],
        'scheduleDate': order_info['scheduleDate'],
        'visitBeginTime': schedule_info['visitBeginTime'],
        'visitEndTime': schedule_info['visitEndTime'],
        'doctorTitle': order_info['doctorTitle'],
        'patientId': order_info['patientId'],
        'transParam': json.dumps({
            "doctorTitle": order_info['doctorTitle'],
            "deptName": order_info['deptName'],
            "birthday": order_info['birthday']
        }, ensure_ascii=False, separators=(',', ':'))
    }
    print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
    print(params)
    resp = requests.post(url, headers=user_data['headers'], data=params, verify="./DigiCert_Global_Root_CA.crt")
    #  {
    #     "orderId": "4849223944605040647",
    #     "totalFee": 1920,
    #     "type": 1
    # }
    # print(resp.content)
    if resp.status_code == 200:
        data = resp.json()
        if 'data' in data:
            data = data['data']
        else:
            print("提交订单失败")
            print(data)
            return False
    else:
        print("提交订单失败")
        print(resp.text)
        return False
    if 'orderId' not in data:
        print("提交订单失败")
        return False
    order_id = data['orderId']
    print("----ok----order_id:", order_id)

    url = 'https://mp.med.gzhc365.com/api/register/registerpayorder?hisId=153&platformSource=1&platformId=153'
    params = {
        'orderId': order_id,
        'bizContent': json.dumps([
            {"key": "费用类型", "value": "预约挂号"},
            {"key": "就诊科室", "value": order_info['deptName']},
            {"key": "医生名称", "value": order_info['doctorName']},
            {"key": "就诊日期", "value": order_info['scheduleDate'] + ' ' + order_info['visitWeekName']},
            {"key": "就诊时段", "value": schedule_info['visitBeginTime'] + '~' + schedule_info['visitEndTime']},
            # "08:00~08:05"
            {"key": "就诊人", "value": order_info['patientName']},
            {"key": "就诊卡号", "value": order_info['patCardNo']},
        ], ensure_ascii=False, separators=(',', ':'))
    }

    open(".data/order_info.json", 'w', encoding='utf-8').write(json.dumps(params))
    print(json.dumps(params))
    while True:
        # 这里也会失败，需要重试
        resp = requests.post(url, headers=user_data['headers'], data=params, verify="./DigiCert_Global_Root_CA.crt")
        # {
        #     "cashierURI": "https://pay.med.gzhc365.com/cashier/index.html?auth=1#/pay/pay",
        #     "payOrderId": "HBGE5TKU6VM022UL3MHWSOSGPSBLKOK"
        # }
        # url = ('https://pay.med.gzhc365.com/cashier/index.html?auth=1#/pay/pay?payOrderId=HBGE5TKU6VM022UL3MHWSOSGPSBLKOK'
        #        '&returnUrl=https%3A%2F%2Fmp.med.gzhc365.com%2Fviews%2Fp153%2Findex.html%3FreturnRandomParam'
        #        '%3D1702303584469%26%26%26auth%3D%23%2Fwaiting%2Fwaiting%3ForderId%3D4849223944605040647%26type%3DYYGH&_k'
        #        '=5sjyvl')
        if resp.status_code == 200:
            data = resp.json()
            if 'data' in data:
                data = data['data']
                url = (data['cashierURI'] + '?payOrderId=' + data['payOrderId']
                       + '&returnUrl=https://mp.med.gzhc365.com/views/p153/index.html?returnRandomParam=1702303584469&&&auth=#/waiting/waiting?type=YYGH&orderId=' + order_id)
                print(url)
                # https://pay.med.gzhc365.com/cashier/index.html?auth=1#/pay/pay?payOrderId=HXLA1TC8GKQQI9W22ULKXUIGWOKRLK2C&returnUrl=https%3A%2F%2Fmp.med.gzhc365.com%2Fviews%2Fp153%2Findex.html%3FreturnRandomParam%3D1702309288639%26%26%26auth%3D%23%2Fwaiting%2Fwaiting%3ForderId%3D4849321955764011014%26type%3DYYGH&_k=njulxs
                # https://pay.med.gzhc365.com/cashier/index.html?auth=1#/pay/pay?payOrderId=HXUIGWG87KKWC2922UL3XLM1VQSALXCY&returnUrl=https%3A%2F%2Fmp.med.gzhc365.com%2Fviews%2Fp153%2Findex.html%3FreturnRandomParam%3D1702303584469%26%26%26auth%3D%23%2Fwaiting%2Fwaiting%3ForderId%3D4849305119487983625%26type%3DYYGH&_k=5sjyvl
                return True
            else:
                print("提交订单失败")
                print(resp.content)
        else:
            print("提交订单失败")
            print(resp.content)
        time.sleep(10)


############################################################################################################
# 以下为辅助函数
############################################################################################################

# 签名
def get_route_sign_param(self, param):
    his_config = self.get_client_config()
    tnow = datetime.datetime.now()
    mth = str(tnow.month - 1).zfill(2)
    t = tnow.strftime('%Y') + mth
    param['t'] = t
    sign = hmac.new(his_config['hisId'].encode(), param.values(), hashlib.md5).hexdigest()
    return urllib.parse.urlencode(param) + '&sign=' + sign


def wrapped_fetch(url, body=None):
    uid = user_data['uid']
    platform_source = 1  # 渠道
    header = user_data['headers']
    wx = platform_source == 1
    if wx:
        header['channel'] = 'wx_gzh'
    else:
        header['channel'] = 'zfb'  # 客户端
    header['uid'] = uid  # 当前用户id
    header['his-id'] = "153"  # 医院id
    header['device-id'] = ''  # 当前设备id
    header['request-id'] = get_guid()
    header['uuid'] = get_guid()

    # param['method'] = param.get('method', 'POST')
    # param['credentials'] = param.get('credentials', 'include')
    # is_normal_post = body is None or isinstance(body, str)
    is_route_api = url.find('?_route=') > -1
    if is_route_api:
        if isinstance(body, str):
            body_obj = query_string2json(urllib.parse.unquote(body))
        else:
            body_obj = body or {}
        if 'sign' not in body_obj:
            tnow = datetime.datetime.now()
            mth = f'0{(tnow.month - 1)}'
            pad_mth = re.sub(r'^\d(\d+?\d$)', r'\1', mth)
            t = f'{tnow.year}{pad_mth}'
            body_obj['t'] = t
            body_obj['sign'] = encryption_obj2md5(body_obj, create_genkey(t, "153"))
            body = json2string(body_obj)

    # req_cont_type = param.get('Content-Type') or param.get('content-type') or ''
    # req_cont_type.find('application/json') < 0 and
    now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    print(now, "Request url:", url)
    print(now, "Request data:", body)
    response = requests.post(
        url,
        data=body, headers=header, verify='DigiCert_Global_Root_CA.crt')
    # 打印响应状态码和响应体
    now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    print(now, "Response status:", response.status_code)
    body = response.text
    print(now, "Response body:", body)
    ret = {}
    if response.status_code != 200:
        return ret
    try:
        resp = json.loads(body)
    except Exception:
        return ret
    if resp and resp['code'] == 999:
        return ret

    if 'data' in resp:
        return resp['data']
    return resp


def get_guid():
    return ''.join(['xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'[i] if i % 2 == 0 else str(random.randint(0, 15)) for i in
                    range(36)])


def query_string2json(string):
    param_arr = string.split('&')
    param_obj = {}
    for i in range(len(param_arr)):
        if '=' in param_arr[i]:
            key, value = param_arr[i].split('=')
            param_obj[key] = value
    return param_obj


def create_genkey(t, his_id):
    key = f'gr3ywga{t}{his_id}'.encode()
    return hashlib.md5(key).hexdigest()


def sort_obj(obj):
    sorted_dict = {k: obj[k] for k in sorted(obj)}
    return sorted_dict


def filter_params(obj):
    return {k: v for k, v in obj.items() if v not in ['', None]}


def json2string(json_str):
    if json_str:
        return '&'.join([f'{urllib.parse.quote(k)}={urllib.parse.quote(v)}' for k, v in json_str.items()])
    return ''


def encryption_obj2md5(obj, basekey):
    string_sign_temp = urllib.parse.unquote(json2string(sort_obj(filter_params(obj))))
    string_sign_temp += '&' + basekey
    return hashlib.md5(string_sign_temp.encode()).hexdigest().upper()


if __name__ == "__main__":
    start()
